Skip to content

API: require auth and identity-bound ownership for POST /api/tasks (match docs contract)#414

Open
pradipthaadhi wants to merge 2 commits intotestfrom
yuliusupwork/myc-4585-api-require-auth-and-identity-bound-ownership-for-post
Open

API: require auth and identity-bound ownership for POST /api/tasks (match docs contract)#414
pradipthaadhi wants to merge 2 commits intotestfrom
yuliusupwork/myc-4585-api-require-auth-and-identity-bound-ownership-for-post

Conversation

@pradipthaadhi
Copy link
Copy Markdown
Collaborator

@pradipthaadhi pradipthaadhi commented Apr 8, 2026

  • Updated the import of the task validation function to validateCreateTaskRequest for clarity.
  • Modified the createTaskHandler to utilize the new validation function, which now includes JSON body validation and authentication context checks.
  • Added new tests for createTaskHandler and validateCreateTaskRequest to ensure proper functionality and error handling.

Summary by CodeRabbit

  • Refactor
    • Task creation now validates requests using a request-level flow that ensures the account association is resolved from authentication context before creating tasks.
  • Bug Fixes
    • Malformed or invalid request payloads now return a clear 400 response with appropriate headers, improving error handling and consistency for clients.

- Updated the import of the task validation function to `validateCreateTaskRequest` for clarity.
- Modified the `createTaskHandler` to utilize the new validation function, which now includes JSON body validation and authentication context checks.
- Added new tests for `createTaskHandler` and `validateCreateTaskRequest` to ensure proper functionality and error handling.
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
recoup-api Ready Ready Preview Apr 10, 2026 5:59am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 8, 2026

📝 Walkthrough

Walkthrough

Validation for task creation was moved into an async request-level validator validateCreateTaskRequest(request), which parses JSON, runs Zod validation, resolves auth context (overwriting account_id), and returns either a NextResponse or the validated body. The handler now awaits this validator instead of parsing request.json() itself.

Changes

Cohort / File(s) Summary
Request-level validation refactor
lib/tasks/createTaskHandler.ts, lib/tasks/validateCreateTaskBody.ts
Replaced body-level validator with an async validateCreateTaskRequest(request) that parses request.json(), performs Zod validation, calls validateAuthContext(request, { accountId }), and returns either a NextResponse or a validated CreateTaskBody with account_id normalized. Handler updated to await this validator and proceed to createTask(validatedBody) on success.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Merge to test to main #350: Similar refactor converting synchronous body validators into async request-aware validators that integrate auth resolution and account_id normalization.
  • add auth validation to get tasks API #345: Same pattern of moving JSON parsing and validation into request-level validators and updating handlers to await them.

Suggested reviewers

  • sweetmantech

Poem

A request walks in, a body to confide,
A validator listens, parses, and guides—
Auth checks whisper, account_id set true,
The handler nods, and the task we pursue. ✨

🚥 Pre-merge checks | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Solid & Clean Code ⚠️ Warning File lib/tasks/validateCreateTaskBody.ts exports validateCreateTaskRequest, violating the file-function naming convention rule. Rename validateCreateTaskBody.ts to validateCreateTaskRequest.ts and update all import statements across the codebase to match.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yuliusupwork/myc-4585-api-require-auth-and-identity-bound-ownership-for-post

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
lib/tasks/validateCreateTaskBody.ts (1)

73-102: Split request-level validation into its own file to preserve SRP and naming consistency.

validateCreateTaskRequest introduces a second exported validator in a ...Body.ts module and is >20 lines while handling multiple responsibilities (JSON parse, body validate, auth validate, account override). Please move it to a dedicated file (for example, validateCreateTaskRequest.ts) and keep validateCreateTaskBody.ts focused on schema/body validation.

As per coding guidelines: lib/**/*.ts: "Apply Single Responsibility Principle (SRP): one exported function per file; each file should do one thing well", **/*.{js,ts,tsx,jsx}: "each file must export ONE primary function, and the file name must match that function", and **/*.{js,ts,tsx,jsx,py,java,cs,go,rb,php}: "Flag functions longer than 20 lines".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/tasks/validateCreateTaskBody.ts` around lines 73 - 102, The
validateCreateTaskRequest function in validateCreateTaskBody.ts mixes JSON
parsing, body validation, auth check and account override and must be moved to
its own file; create a new file named e.g. validateCreateTaskRequest.ts
exporting the single function validateCreateTaskRequest, have it call
validateCreateTaskBody(body) for schema validation and
validateAuthContext(request, { accountId: validatedBody.account_id }) for auth,
reuse getCorsHeaders for the JSON parse error response, and return the merged
object with account_id: auth.accountId; remove the validateCreateTaskRequest
export from validateCreateTaskBody.ts so that file only exports
validateCreateTaskBody.
lib/tasks/createTaskHandler.ts (1)

21-53: Consider trimming createTaskHandler to keep it under the 20-line guideline and more focused.

The handler currently mixes validation orchestration, persistence call, and response shaping. Extracting response builders (success/error) would keep this function tighter and easier to maintain.

As per coding guidelines: **/*.{js,ts,tsx,jsx,py,java,cs,go,rb,php}: "Flag functions longer than 20 lines" and lib/**/*.ts: "Single responsibility per function".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/tasks/createTaskHandler.ts` around lines 21 - 53, createTaskHandler is
doing validation, persistence and response shaping in one function; extract the
success and error response builders into small helpers (e.g.,
buildCreateTaskSuccessResponse and buildCreateTaskErrorResponse) and move the
NextResponse.json + getCorsHeaders logic into those helpers so createTaskHandler
only orchestrates validateCreateTaskRequest and createTask and returns the
helper results; keep existing behavior (return validated NextResponse early,
call createTask with validatedBody, log error in the catch and pass
error.message into the error builder) and reference createTaskHandler,
validateCreateTaskRequest, createTask, getCorsHeaders when locating where to
extract helpers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@lib/tasks/createTaskHandler.ts`:
- Around line 21-53: createTaskHandler is doing validation, persistence and
response shaping in one function; extract the success and error response
builders into small helpers (e.g., buildCreateTaskSuccessResponse and
buildCreateTaskErrorResponse) and move the NextResponse.json + getCorsHeaders
logic into those helpers so createTaskHandler only orchestrates
validateCreateTaskRequest and createTask and returns the helper results; keep
existing behavior (return validated NextResponse early, call createTask with
validatedBody, log error in the catch and pass error.message into the error
builder) and reference createTaskHandler, validateCreateTaskRequest, createTask,
getCorsHeaders when locating where to extract helpers.

In `@lib/tasks/validateCreateTaskBody.ts`:
- Around line 73-102: The validateCreateTaskRequest function in
validateCreateTaskBody.ts mixes JSON parsing, body validation, auth check and
account override and must be moved to its own file; create a new file named e.g.
validateCreateTaskRequest.ts exporting the single function
validateCreateTaskRequest, have it call validateCreateTaskBody(body) for schema
validation and validateAuthContext(request, { accountId:
validatedBody.account_id }) for auth, reuse getCorsHeaders for the JSON parse
error response, and return the merged object with account_id: auth.accountId;
remove the validateCreateTaskRequest export from validateCreateTaskBody.ts so
that file only exports validateCreateTaskBody.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6dc5a055-e9da-4b62-b26a-fdc18441ea59

📥 Commits

Reviewing files that changed from the base of the PR and between a3eec5d and c29d314.

⛔ Files ignored due to path filters (2)
  • lib/tasks/__tests__/createTaskHandler.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
  • lib/tasks/__tests__/validateCreateTaskRequest.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
📒 Files selected for processing (2)
  • lib/tasks/createTaskHandler.ts
  • lib/tasks/validateCreateTaskBody.ts

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 4 files

Confidence score: 4/5

  • This PR appears safe to merge with low functional risk; the reported issues are maintainability/style concerns rather than clear runtime bugs or regressions.
  • The highest-severity findings are in lib/tasks/validateCreateTaskBody.ts and indicate file-size/SRP convention drift, which can make future changes harder to reason about and review.
  • Test files lib/tasks/__tests__/validateCreateTaskRequest.test.ts and lib/tasks/__tests__/createTaskHandler.test.ts exceed the 100-line project guideline, which may reduce readability but is not likely to break behavior today.
  • Pay close attention to lib/tasks/validateCreateTaskBody.ts, lib/tasks/__tests__/validateCreateTaskRequest.test.ts, and lib/tasks/__tests__/createTaskHandler.test.ts - refactor for size/SRP alignment to keep maintenance risk from growing.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="lib/tasks/__tests__/createTaskHandler.test.ts">

<violation number="1" location="lib/tasks/__tests__/createTaskHandler.test.ts:1">
P2: Custom agent: **Enforce Clear Code Style and Maintainability Practices**

Newly added test file exceeds the rule’s 100-line maximum (120 lines), violating the maintainability size limit.</violation>
</file>

<file name="lib/tasks/__tests__/validateCreateTaskRequest.test.ts">

<violation number="1" location="lib/tasks/__tests__/validateCreateTaskRequest.test.ts:1">
P2: Custom agent: **Enforce Clear Code Style and Maintainability Practices**

New test module exceeds the Rule 3 file-length limit (<100 lines), reducing readability and maintainability.</violation>
</file>

<file name="lib/tasks/validateCreateTaskBody.ts">

<violation number="1" location="lib/tasks/validateCreateTaskBody.ts:73">
P2: Custom agent: **Enforce Clear Code Style and Maintainability Practices**

File exceeds the custom 100-line maintainability limit after PR additions.</violation>

<violation number="2" location="lib/tasks/validateCreateTaskBody.ts:73">
P2: Per the project's SRP convention, `validateCreateTaskRequest` should live in its own file `lib/tasks/validateCreateTaskRequest.ts`. The file-naming rule requires each file to export one primary function whose name matches the filename.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Client
    participant Handler as createTaskHandler
    participant Validator as validateCreateTaskRequest
    participant Auth as validateAuthContext
    participant DB as createTask (DB Service)

    Note over Client,DB: POST /api/tasks Flow

    Client->>Handler: POST request (JSON + Auth Headers)
    
    Handler->>Validator: NEW: validateCreateTaskRequest(request)
    
    Validator->>Validator: Parse JSON body
    alt Invalid JSON
        Validator-->>Handler: 400 Bad Request
        Handler-->>Client: Error response
    end

    Validator->>Validator: Zod schema validation
    alt Schema validation fails
        Validator-->>Handler: 400 Bad Request
        Handler-->>Client: Error response
    end

    Validator->>Auth: NEW: validateAuthContext(request, { accountId })
    Note right of Auth: Verifies API Key/JWT and<br/>identity-bound ownership
    
    alt Auth or Ownership failure
        Auth-->>Validator: 401 Unauthorized / 403 Forbidden
        Validator-->>Handler: Error Response
        Handler-->>Client: Error response
    else Auth Success
        Auth-->>Validator: Resolved Auth Context (accountId, etc.)
        Validator-->>Handler: Validated CreateTaskBody
    end

    Handler->>DB: createTask(validatedBody)
    
    alt DB Success
        DB-->>Handler: Created Task Record
        Handler-->>Client: 200 OK (Success + Task Data)
    else DB Failure (Exception)
        DB-->>Handler: Error
        Handler-->>Client: 500 Internal Server Error
    end
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

@@ -0,0 +1,120 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Custom agent: Enforce Clear Code Style and Maintainability Practices

Newly added test file exceeds the rule’s 100-line maximum (120 lines), violating the maintainability size limit.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/tasks/__tests__/createTaskHandler.test.ts, line 1:

<comment>Newly added test file exceeds the rule’s 100-line maximum (120 lines), violating the maintainability size limit.</comment>

<file context>
@@ -0,0 +1,120 @@
+import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
+import { NextRequest, NextResponse } from "next/server";
+import { createTaskHandler } from "@/lib/tasks/createTaskHandler";
</file context>
Fix with Cubic

@@ -0,0 +1,257 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Custom agent: Enforce Clear Code Style and Maintainability Practices

New test module exceeds the Rule 3 file-length limit (<100 lines), reducing readability and maintainability.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/tasks/__tests__/validateCreateTaskRequest.test.ts, line 1:

<comment>New test module exceeds the Rule 3 file-length limit (<100 lines), reducing readability and maintainability.</comment>

<file context>
@@ -0,0 +1,257 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { NextRequest, NextResponse } from "next/server";
+import { validateCreateTaskRequest } from "@/lib/tasks/validateCreateTaskBody";
</file context>
Fix with Cubic

* @param request - The incoming Next.js request
* @returns Error response or {@link CreateTaskBody} with account_id set from resolved auth context
*/
export async function validateCreateTaskRequest(
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Per the project's SRP convention, validateCreateTaskRequest should live in its own file lib/tasks/validateCreateTaskRequest.ts. The file-naming rule requires each file to export one primary function whose name matches the filename.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/tasks/validateCreateTaskBody.ts, line 73:

<comment>Per the project's SRP convention, `validateCreateTaskRequest` should live in its own file `lib/tasks/validateCreateTaskRequest.ts`. The file-naming rule requires each file to export one primary function whose name matches the filename.</comment>

<file context>
@@ -62,3 +63,40 @@ export function validateCreateTaskBody(body: unknown): NextResponse | CreateTask
+ * @param request - The incoming Next.js request
+ * @returns Error response or {@link CreateTaskBody} with account_id set from resolved auth context
+ */
+export async function validateCreateTaskRequest(
+  request: NextRequest,
+): Promise<NextResponse | CreateTaskBody> {
</file context>
Fix with Cubic

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YAGNI principle

  • is this validateCreateTaskBody function still being used?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, agreed on YAGNI. I inlined the Zod validation into validateCreateTaskRequest and removed the separate validateCreateTaskBody helper.

- Removed the separate validateCreateTaskBody function and integrated its logic directly into validateCreateTaskRequest.
- Simplified error handling for validation failures, maintaining response structure.
- Ensured consistent validation flow for task creation requests.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
lib/tasks/validateCreateTaskBody.ts (1)

46-87: Function exceeds the 20-line limit.

validateCreateTaskRequest spans ~42 lines and consolidates three distinct responsibilities: JSON parsing, Zod schema validation, and auth context validation with account_id override. While bundling these for request-level validation is pragmatic, consider extracting the JSON parsing and schema validation into a helper to keep this function focused on orchestration and under the line limit.

♻️ Suggested refactor to reduce function length

Extract JSON parsing and schema validation into a separate helper (e.g., parseAndValidateBody):

+async function parseAndValidateBody(
+  request: NextRequest,
+): Promise<NextResponse | z.infer<typeof createTaskBodySchema>> {
+  let body: unknown;
+  try {
+    body = await request.json();
+  } catch {
+    return NextResponse.json(
+      { status: "error", error: "Invalid JSON body" },
+      { status: 400, headers: getCorsHeaders() },
+    );
+  }
+
+  const validationResult = createTaskBodySchema.safeParse(body);
+  if (!validationResult.success) {
+    const firstError = validationResult.error.issues[0];
+    return NextResponse.json(
+      {
+        status: "error",
+        missing_fields: firstError.path,
+        error: firstError.message,
+      },
+      { status: 400, headers: getCorsHeaders() },
+    );
+  }
+  return validationResult.data;
+}
+
 export async function validateCreateTaskRequest(
   request: NextRequest,
 ): Promise<NextResponse | CreateTaskBody> {
-  let body: unknown;
-  try {
-    body = await request.json();
-  } catch {
-    return NextResponse.json(
-      { status: "error", error: "Invalid JSON body" },
-      { status: 400, headers: getCorsHeaders() },
-    );
-  }
-
-  const validationResult = createTaskBodySchema.safeParse(body);
-  if (!validationResult.success) {
-    const firstError = validationResult.error.issues[0];
-    return NextResponse.json(
-      {
-        status: "error",
-        missing_fields: firstError.path,
-        error: firstError.message,
-      },
-      {
-        status: 400,
-        headers: getCorsHeaders(),
-      },
-    );
-  }
-
-  const validatedBody = validationResult.data;
+  const validatedBody = await parseAndValidateBody(request);
+  if (validatedBody instanceof NextResponse) {
+    return validatedBody;
+  }

   const auth = await validateAuthContext(request, {
     accountId: validatedBody.account_id,
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/tasks/validateCreateTaskBody.ts` around lines 46 - 87, The
validateCreateTaskRequest function is too long and mixes JSON parsing, Zod
validation, and auth logic; extract the JSON parsing and schema validation into
a new helper (e.g., parseAndValidateBody) that performs request.json() with the
existing error response (using NextResponse and getCorsHeaders) and runs
createTaskBodySchema.safeParse returning either a validated CreateTaskBody or a
NextResponse error; then simplify validateCreateTaskRequest to call
parseAndValidateBody, short-circuit if it returns a NextResponse, and only run
validateAuthContext and the account_id override (using validateAuthContext and
returning the merged body) so the main function stays under 20 lines.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/tasks/validateCreateTaskBody.ts`:
- Around line 46-48: The file validateCreateTaskBody.ts exports a function named
validateCreateTaskRequest, so rename the file to validateCreateTaskRequest.ts to
match the exported function name (validateCreateTaskRequest) and update any
imports that reference the old filename (validateCreateTaskBody) throughout the
codebase to the new filename to avoid import errors.

---

Nitpick comments:
In `@lib/tasks/validateCreateTaskBody.ts`:
- Around line 46-87: The validateCreateTaskRequest function is too long and
mixes JSON parsing, Zod validation, and auth logic; extract the JSON parsing and
schema validation into a new helper (e.g., parseAndValidateBody) that performs
request.json() with the existing error response (using NextResponse and
getCorsHeaders) and runs createTaskBodySchema.safeParse returning either a
validated CreateTaskBody or a NextResponse error; then simplify
validateCreateTaskRequest to call parseAndValidateBody, short-circuit if it
returns a NextResponse, and only run validateAuthContext and the account_id
override (using validateAuthContext and returning the merged body) so the main
function stays under 20 lines.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3a833664-6819-4fc3-b29e-2adbe4670fd0

📥 Commits

Reviewing files that changed from the base of the PR and between c29d314 and c79850c.

📒 Files selected for processing (1)
  • lib/tasks/validateCreateTaskBody.ts

Comment on lines +46 to +48
export async function validateCreateTaskRequest(
request: NextRequest,
): Promise<NextResponse | CreateTaskBody> {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

File name does not match exported function name.

The file is named validateCreateTaskBody.ts but the primary exported function is validateCreateTaskRequest. Per coding guidelines, the file name must match the exported function name. Rename this file to validateCreateTaskRequest.ts to maintain consistency and discoverability.

As per coding guidelines: "File naming rule: The file name MUST match the exported function name."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/tasks/validateCreateTaskBody.ts` around lines 46 - 48, The file
validateCreateTaskBody.ts exports a function named validateCreateTaskRequest, so
rename the file to validateCreateTaskRequest.ts to match the exported function
name (validateCreateTaskRequest) and update any imports that reference the old
filename (validateCreateTaskBody) throughout the codebase to the new filename to
avoid import errors.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Requires human review: Auto-approval blocked by 3 unresolved issues from previous reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants